#include <tool/MeshXMLLoader.h>
#include <graphics/Engine.h>
#include <system/Log.h>

namespace ne
{
    bool MeshXMLLoader::loadResource(Resource* resource)
    {
        if (!resource) return false;
        Mesh *pMesh = dynamic_cast<Mesh*>(resource);
        if (!pMesh) return false;

        XMLDocument doc(pMesh->getFileName().c_str());
        if (!doc.LoadFile(TIXML_ENCODING_UTF8))
        {
            Log::Out(LL_WARNING,
                "Load MeshXML (%s) file (%s) failed",
                pMesh->getName().c_str(), pMesh->getFileName().c_str());
            return false;
        }

        XMLElement *eMesh = doc.FirstChildElement("Mesh");
        if (!eMesh) return false;

        int result = 0;
        std::string meshName;
        std::string meshMaterialName;
        result = eMesh->QueryStringAttribute("name", &meshName);
        std::cout << meshName << std::endl;
        result = eMesh->QueryStringAttribute("material", &meshMaterialName);
        std::cout << meshMaterialName << std::endl;

        XMLElement *eVertexData = eMesh->FirstChildElement("VertexData");
        if (!eVertexData) return false;

        std::string vertexPrimitive;
        result = eVertexData->QueryStringAttribute("primitive", &vertexPrimitive);
        std::cout << vertexPrimitive << std::endl;
        uint32_t numAttribute = 0;
        result = eVertexData->QueryUnsignedAttribute("numAttribute", &numAttribute);
        std::cout << numAttribute << std::endl;
        uint32_t numSubMesh = 0;
        result = eVertexData->QueryUnsignedAttribute("numSubMesh", &numSubMesh);
        std::cout << numSubMesh << std::endl;

        VertexDataPtr pVertexData(new VertexData(VertexAttribute::GetPrimitiveType(vertexPrimitive)));
        pMesh->setVertexData(pVertexData);

        XMLElement *eAttribute = eVertexData->FirstChildElement("VertexAttribute");
        for (uint32_t i=0; i<numAttribute; ++i)
        {
            if (!eAttribute) return false;

            std::string attributeSemantic;
            result = eAttribute->QueryStringAttribute("semantic", &attributeSemantic);
            AttributeSemantic semantic = VertexAttribute::GetAttributeSemantic(attributeSemantic);
            std::cout << attributeSemantic << std::endl;
            std::string attributeType;
            result = eAttribute->QueryStringAttribute("type", &attributeType);
            AttributeType type = VertexAttribute::GetAttributeType(attributeType);
            uint32_t attributeSize = VertexAttribute::GetAttributeSize(type);
            std::cout << attributeType << std::endl;
            uint32_t count = 0;
            result = eAttribute->QueryUnsignedAttribute("count", &count);
            std::cout << count << std::endl;
            uint32_t vertexBufferSize = attributeSize * count;
            uint32_t dataCount = VertexAttribute::GetGLDataCount(type) * count;

            GLBufferObjectPtr pVertexBuffer(GLBufferObjectManager::GetSingleton().createBufferObject(
                BOT_ARRAY_BUFFER, BOU_STATIC_DRAW, vertexBufferSize));

            const char *pText = eAttribute->GetText();
            char *pToken = strtok(const_cast<char*>(pText), " ,:;");

            switch (type)
            {
                case VAT_CHAR1:
                case VAT_CHAR2:
                case VAT_CHAR3:
                case VAT_CHAR4:
                case VAT_BYTE1:
                case VAT_BYTE2:
                case VAT_BYTE3:
                case VAT_BYTE4:
                {
                    uint8_t* pVBuffer = static_cast<uint8_t*>(pVertexBuffer->lock(BOA_WRITE_ONLY, 0, vertexBufferSize, true));
                    for (uint32_t j=0; j<dataCount; ++j)
                    {
                        uint32_t d = 0;
                        sscanf(pToken, "%u", &d);
                        *pVBuffer++ = uint8_t(d);
                        pToken = strtok(0, " ,:;");
                    }
                    break;
                }

                case VAT_SHORT1:
                case VAT_SHORT2:
                case VAT_SHORT3:
                case VAT_SHORT4:
                case VAT_UNSIGNED_SHORT1:
                case VAT_UNSIGNED_SHORT2:
                case VAT_UNSIGNED_SHORT3:
                case VAT_UNSIGNED_SHORT4:
                {
                    uint16_t* pVBuffer = static_cast<uint16_t*>(pVertexBuffer->lock(BOA_WRITE_ONLY, 0, vertexBufferSize, true));
                    for (uint32_t j=0; j<dataCount; ++j)
                    {
                        uint32_t d = 0;
                        sscanf(pToken, "%u", &d);
                        *pVBuffer++ = uint16_t(d);
                        pToken = strtok(0, " ,:;");
                    }
                    break;
                }

                case VAT_INT1:
                case VAT_INT2:
                case VAT_INT3:
                case VAT_INT4:
                case VAT_UNSIGNED_INT1:
                case VAT_UNSIGNED_INT2:
                case VAT_UNSIGNED_INT3:
                case VAT_UNSIGNED_INT4:
                {
                    uint32_t* pVBuffer = static_cast<uint32_t*>(pVertexBuffer->lock(BOA_WRITE_ONLY, 0, vertexBufferSize, true));
                    for (uint32_t j=0; j<dataCount; ++j)
                    {
                        uint32_t d = 0;
                        sscanf(pToken, "%u", &d);
                        *pVBuffer++ = uint32_t(d);
                        pToken = strtok(0, " ,:;");
                    }
                    break;
                }

                case VAT_DOUBLE1:
                case VAT_DOUBLE2:
                case VAT_DOUBLE3:
                case VAT_DOUBLE4:
                {
                    double* pVBuffer = static_cast<double*>(pVertexBuffer->lock(BOA_WRITE_ONLY, 0, vertexBufferSize, true));
                    for (uint32_t j=0; j<dataCount; ++j)
                    {
                        double d = 0.0f;
                        sscanf(pToken, "%lf", &d);
                        *pVBuffer++ = double(d);
                        pToken = strtok(0, " ,:;");
                    }
                    break;
                }

                default:
                {
                    real* pVBuffer = static_cast<real*>(pVertexBuffer->lock(BOA_WRITE_ONLY, 0, vertexBufferSize, true));
                    for (uint32_t j=0; j<dataCount; ++j)
                    {
                        real d = 0.0f;
                        sscanf(pToken, "%f", &d);
                        *pVBuffer++ = real(d);
                        pToken = strtok(0, " ,:;");
                    }
                    break;
                }
            }

            pVertexBuffer->unlock();

            pVertexData->createAttribute(pVertexBuffer->getSource(),
                semantic, type, count, 0, 0, false);

            eAttribute = eAttribute->NextSiblingElement("VertexAttribute");
        }

        XMLElement *eSubMesh = eMesh->FirstChildElement("SubMesh");
        for (uint32_t i=0; i<numSubMesh; ++i)
        {
            if (!eSubMesh) return false;

            std::string subMeshName;
            result = eSubMesh->QueryStringAttribute("name", &subMeshName);
            std::cout << subMeshName << std::endl;
            std::string subMeshMaterialName;
            result = eSubMesh->QueryStringAttribute("material", &subMeshMaterialName);
            std::cout << subMeshMaterialName << std::endl;

            XMLElement *eIndexData = eSubMesh->FirstChildElement("IndexData");
            if (!eIndexData) return false;

            std::string indexPrimitive;
            result = eIndexData->QueryStringAttribute("primitive", &indexPrimitive);
            std::cout << indexPrimitive << std::endl;
            std::string indexType;
            result = eIndexData->QueryStringAttribute("type", &indexType);
            AttributeType type = VertexAttribute::GetAttributeType(indexType);
            uint32_t attributeSize = VertexAttribute::GetAttributeSize(type);
            std::cout << indexType << std::endl;
            uint32_t indexCount = 0;
            result = eIndexData->QueryUnsignedAttribute("count", &indexCount);
            std::cout << indexCount << std::endl;
            uint32_t indexBufferSize = attributeSize * indexCount;

            GLBufferObjectPtr pIndexBuffer(GLBufferObjectManager::GetSingleton().createBufferObject(
                BOT_ELEMENT_ARRAY_BUFFER, BOU_STATIC_DRAW, indexBufferSize));

            const char *pIndexDataText = eIndexData->GetText();
            char *pToken = strtok(const_cast<char*>(pIndexDataText), " ,:;");

            switch (type)
            {
                case VAT_BYTE:
                {
                    uint8_t* pIBuffer = static_cast<uint8_t*>(pIndexBuffer->lock(BOA_WRITE_ONLY, 0, indexBufferSize, true));
                    for (uint32_t j=0; j<indexCount; ++j)
                    {
                        uint32_t d = 0;
                        sscanf(pToken, "%u", &d);
                        *pIBuffer++ = uint8_t(d);
                        pToken = strtok(0, " ,:;");
                    }
                    break;
                }

                case VAT_UNSIGNED_SHORT:
                {
                    uint16_t* pIBuffer = static_cast<uint16_t*>(pIndexBuffer->lock(BOA_WRITE_ONLY, 0, indexBufferSize, true));
                    for (uint32_t j=0; j<indexCount; ++j)
                    {
                        uint32_t d = 0;
                        sscanf(pToken, "%u", &d);
                        *pIBuffer++ = uint16_t(d);
                        pToken = strtok(0, " ,:;");
                    }
                    break;
                }

                default:
                {
                    uint32_t* pIBuffer = static_cast<uint32_t*>(pIndexBuffer->lock(BOA_WRITE_ONLY, 0, indexBufferSize, true));
                    for (uint32_t j=0; j<indexCount; ++j)
                    {
                        uint32_t d = 0;
                        sscanf(pToken, "%u", &d);
                        *pIBuffer++ = uint32_t(d);
                        pToken = strtok(0, " ,:;");
                    }
                    break;
                }
            }

            pIndexBuffer->unlock();

            SubMeshPtr pSubMesh(new SubMesh(subMeshName));
            IndexDataPtr pIndexData(new IndexData(VertexAttribute::GetPrimitiveType(indexPrimitive),
                pIndexBuffer->getSource(), type, indexCount, 0));
            pSubMesh->setIndexData(pIndexData);
            pMesh->addChild(pSubMesh);

            eSubMesh = eSubMesh->NextSiblingElement("SubMesh");
        }

        return true;
    }
}
